package com.wngbms.feigndemo.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class MethodHandler {

    public static Map<String, MethodMeta> apply(Class<?> type) {
        Map<String, MethodMeta> methodMetaMap = new HashMap<>();

        Method[] methods = type.getMethods();
        for (Method method : methods) {
            if (method.getDeclaringClass() == Object.class) {
                log.info("method:{} is declared in Object", method.getName());
                continue;
            }
            if ((method.getModifiers() & Modifier.STATIC) != 0) {
                log.info("method:{} is static", method.getName());
                continue;
            }
            if (((method.getModifiers()
                    & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | 0x00001000))
                    == Modifier.PUBLIC) && method.getDeclaringClass().isInterface()) {
                log.info("method:{} is default", method.getName());
                continue;
            }
            methodMetaMap.put(method.getName(), parse(method));
        }

        return methodMetaMap;
    }

    public static MethodMeta parse(Method method) {
        MethodMeta methodMeta = new MethodMeta();
        methodMeta.setMethodName(method.getName());

        Annotation[] annotations = method.getAnnotations();
        if (annotations != null && annotations.length > 0) {
            List<String> collect = Arrays.stream(annotations).map(Annotation::toString).collect(Collectors.toList());
            methodMeta.setMethodAnnotations(collect);
        }

        Class<?>[] parameterTypes = method.getParameterTypes();
        Type[] genericExceptionTypes = method.getGenericExceptionTypes();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();

        methodMeta.setParameterTypes(parameterTypes);
        methodMeta.setGenericExceptionTypes(genericExceptionTypes);
        methodMeta.setParameterAnnotations(parameterAnnotations);

        return methodMeta;
    }

}
